package FlowGraph;

import java.util.*;
import java.io.*;

import ptolemy.actor.*;

import antlr.collections.AST;
import antlr.*;

import SymbolTable.*;
import JavaGrammar.*;
import JavaGrammar.TreeScanners.*;
import FlowGraph.Nodes.*;
import FlowGraph.EdgeInfo.*;
import FlowGraph.StatementInfo.*;
import FlowGraph.SSA.*;
import util.*;
import MethodGraph.*;
import db.ClassData;

//////////////////////////////////////////////////////////////////////////
//// FlowGraph
/**


@author Ivan Jeukens
@version v 0.1 03/10/2001
*/
public class FlowGraph {

    /*
    public FlowGraph(String name, ClassData owner, boolean isConstructor) {
        _methodName = name;
        _nodes = new LinkedList();
        _edges = new LinkedList();
        _owner = owner;
        _isConstructor = isConstructor;
        _key = new String(name + owner.getName());
    }*/

    public FlowGraph(String name, AST stats, ClassData owner,
            SymbolTable methodParameters, boolean isConstructor) {
        _methodName = name;
        _stats = stats;
        _owner = owner;
        _isConstructor = isConstructor;

        _nodes = new LinkedList();
        _edges = new LinkedList();

        _key = new String(name + owner.getName());

        _methodParameters = methodParameters;
        _notBuild = true;
        _opPerformed = false;
    }

    ///////////////////////////////////////////////////////////////////
    ////                        public  methods                    ////

    // constroi um flow graph, e para cada no de chamada de metodo, o
    // flowgraph correspondente.
    public void build() {
        if(_notBuild) {
            FlowGraphFactory fac = new FlowGraphFactory();
            fac.build(this, _stats, _owner, _methodParameters);

            // o methodParameters esta sendo alterado durante o build....e um
            // bug...
            _methodParameters = _source.getSymbolTable();
            _notBuild = false;
        }
    }

    public boolean isBuild() {
        return !_notBuild;
    }
    
    public boolean opPerformed() {
        return _opPerformed;
    }

    public void setOpPerformed() {
        _opPerformed = true;
    }

    public FlowGraphEdge connect(FlowGraphNode from, FlowGraphNode to) {
        FlowGraphEdge edge = new FlowGraphEdge(from, to);
        from.addOutputEdge(edge);
        to.addInputEdge(edge);
        _edges.add(edge);

        return edge;
    }

    public boolean disconnect(FlowGraphNode from, FlowGraphNode to) {
        FlowGraphEdge edge = from.removeOutputEdge(to);
        to.removeInputEdge(edge);

        _edges.remove(edge);
        return edge.changeScope();
    }

    public void replaceConnection(FlowGraphNode from, FlowGraphNode to,
            FlowGraphNode newTo) {
        FlowGraphEdge edge = to.removeInputEdge(from);
        // isso ja concerta no from ...
        edge.setTo(newTo);
        newTo.addInputEdge(edge);
    }
    
    public void replaceOutputConnection(FlowGraphNode from, FlowGraphNode to,
            FlowGraphNode newFrom) {
        FlowGraphEdge edge = from.removeOutputEdge(to);
        edge.setFrom(newFrom);
        newFrom.addOutputEdge(edge);
    }

    public ClassData getClassInfo() {
        return _owner;
    }
    
    public void setStatements(AST stats) {
        _stats = stats;
    }

    public void addNode(FlowGraphNode node) {
        _addNode(node);
    }
    
    public void setSource(FlowGraphNode source) {
        _source = source;
    }

    public void setSink(FlowGraphNode sink) {
        _sink = sink;
    }

    public int size() {
        return _nodes.size();
    }
    
    public FlowGraphNode getNode(int index) {
        return (FlowGraphNode) _nodes.get(index);
    }
    
    public Iterator nodesIterator() {
        return _nodes.iterator();
    }

    public FlowGraphNode getSource() {
        return _source;
    }
    
    public FlowGraphNode getSink() {
        return _sink;
    }

    public String toString() {
        return _methodName;
    }

    public void setUniqueCount(int value) {
        _uniqueCount = value;
    }

    public int getUniqueCount() {
        return _uniqueCount;
    }

    public void incrementUniqueCount() {
        _uniqueCount++;
    }

    public void setUniqueSCCount(int value) {
        _uniqueSCCount = value;
    }

    public void visitNodes(LinkedList collectors) {
        Object [] col = (Object []) collectors.toArray();
        for(int i = 0;i < _nodes.size();i++) {
            FlowGraphNode node = (FlowGraphNode) _nodes.get(i);
            for(int j = 0;j < col.length;j++) {
                ((InfoCollector)col[j]).visitFGNode(node);
            }
        }
    }

    public void debug(String basepath, int version) {
        try {
            String fname = new String(basepath + "/" + 
                _methodName + "-v" + version + ".dot");
            File dot = new File(fname);
            FileOutputStream fs = new FileOutputStream(dot);
            PrintStream ps = new PrintStream(fs);

            File f = new File(new String(basepath + "/" +
                _methodName + "-v" + version + ".nodes"));
            FileOutputStream fs2 = new FileOutputStream(f);
            DataOutputStream dout = new DataOutputStream(fs2);

            f = new File(new String(basepath + "/" +
                _methodName + "-v" + version + ".edges"));
            fs2 = new FileOutputStream(f);
            DataOutputStream dout2 = new DataOutputStream(fs2);

            _debug(ps, dout, dout2);
            if(_ssa != null) {
                _ssa.debug(basepath, version);
            }
            if(_methodGraph != null) {
                _methodGraph.debug(basepath, version);
            }

            ps.close();
            fs.close();
            dout.close();
            dout2.close();

            // depois de gerar os .dot, roda o dot para fazer o layout
            Runtime run = Runtime.getRuntime();
            try {
               Process p = run.exec("dot " + fname + " -o t1");
               p.waitFor();
               p = run.exec("rm " + fname);
               p.waitFor();
               p = run.exec("mv t1 " + fname);
               p.waitFor();
            }
            catch(InterruptedException ex) {
                System.out.println("Exception : " + ex);
            }
        }
        catch(IOException ex) {
            ex.printStackTrace();
        }
    }

    public void printGraph() {
        System.out.println("--- FLOW GRAPH for method : " + _methodName);
        for(int i = 0;i < _nodes.size();i++) {
            FlowGraphNode node = (FlowGraphNode) _nodes.get(i);
            _printGraphNode(node, System.out, true);
        }
    }

    public String getMethodName() {
        return _methodName;
    }

    public boolean isConstructor() {
        return _isConstructor;
    }

    // Order topologica a partir do source node.
    public LinkedList getTopologicalOrder(boolean forceComputation) {
        if(_topologicalOrder != null && !forceComputation) {
            return _topologicalOrder;
        }
        _topologicalOrder = new LinkedList();

        HashMap marked = new HashMap();
        LinkedList process = new LinkedList();

        _topologicalOrder.add(_source);
        marked.put(_source, null);
        for(int i = 0;i < _source.outputSize();i++) {
            process.add(_source.getOutputNode(i));
        }
        while(process.size() > 0) {
            FlowGraphNode n = (FlowGraphNode) process.remove(0);
            if(marked.containsKey(n)) continue;

            // Verifica se todos os nos antecessores foram processados.
            // (if sem else)
            boolean ok = true;
            for(int i = 0;i < n.inputSize();i++) {
                FlowGraphEdge edge = n.getInputEdge(i);
                if(edge.isDeleted() || edge.isBack()) continue;

                FlowGraphNode in = edge.getFrom();
                if(in.isDeleted() && (in.getType() != FlowGraphNode.IF_END)) continue;

                // Se for um if com returns etc.... entao nao considera...
                if((in.getType() == FlowGraphNode.IF_END) &&
                   (in.inputSize() == 0)) {
                    continue;
                }

                if(!marked.containsKey(in)) {
                    ok = false;
                    break;
                }
            }

            if(ok) {
                marked.put(n, null);
                _topologicalOrder.add(n);

                Iterator ite = n.outputEdgesIterator();
                while(ite.hasNext()) {
                    FlowGraphEdge edge = (FlowGraphEdge) ite.next();
                    if(edge.isBack() || edge.isDeleted()) {
                        continue;
                    }
                    process.add(edge.getTo());
                }
            }
        }

        return _topologicalOrder;
    }

    public void generateCode(LinkedList lines, int ident) {
        if(_notBuild) {
            Line l = new Line("Not processed", null, null, 1, 4,
                               lines.size());
            lines.add(l);
            return;
        }
        _ident = ident;
        _genPrinter = new StatPrinter();
        _tmpList = new LinkedList();
        _genPrinter.setLines(_tmpList);

        _statPrinter = new StatPrinter();
        _statPrinter.setLines(lines);

        _codeGen(_source.getOutputNode(0), _sink, lines);
    }

    // Um metodo de depuracao para ver o conteudo de todas as symbol tables
    public void dumpSTs() {
        try {
            File f = new File("ST" + _methodName + ".txt");
            FileOutputStream fos = new FileOutputStream(f);
            PrintStream ps = new PrintStream(fos);

            for(int i = 0;i < _nodes.size();i++) {
                FlowGraphNode node = (FlowGraphNode) _nodes.get(i);
                _printGraphNode(node, ps, false);
                SymbolTable st = node.getSymbolTable();
                if(st != null) {
                    ps.println("ST: " + st.toString());
                }
                else {
                    ps.println("ST: null");
                }
            }
        } 
        catch(IOException ex) {
            System.out.println("dumpSTs -> " + ex);
        }
    }

    public void buildSSA() {
        _ssa = new SSA(this);
    }

    public SSA getSSA() {
        return _ssa;
    }

    public LinkedList getAllMCNodes() {
        LinkedList ret = new LinkedList();

        LinkedList process = new LinkedList();
        HashMap processed = new HashMap();
        process.add(_source);

        while(process.size() > 0) {
            FlowGraphNode node = (FlowGraphNode) process.removeFirst();
            if( processed.containsKey(node) ) continue;
            processed.put(node, node);

            // metodos e chamadas de construtores
            if(node.getType() == FlowGraphNode.METHOD_CALL) {
                ret.add(node);
            }

            for(int i = 0;i < node.outputSize();i++) {
                FlowGraphNode outn = node.getOutputNode(i);
                process.add(outn);

                // O addExceptionEdges ainda nao foi executado. Por isso
                // os catches ainda nao estao conectados
                if(node.getType() == FlowGraphNode.TRY_BEGIN) {
                    TryBeginNode tbeg = (TryBeginNode) node;
                    for(int k = 0;k < tbeg.catchSize();k++) {
                        outn = tbeg.getCatch(k);
                        process.add(outn);
                    }
                    if(tbeg.getFinally() != null) {
                        outn = tbeg.getFinally();
                        process.add(outn);
                    }
                }
            }
        }

        return ret;
    }
    
    // Faco o parse de cada no de chamada de metodo, e construo o respec
    public void parseMC(ClassData cdata) {
        LinkedList process = new LinkedList();
        HashMap processed = new HashMap();
        process.add(_source);

        while(process.size() > 0) {
            FlowGraphNode node = (FlowGraphNode) process.removeFirst();
            if( processed.containsKey(node) ) continue;
            processed.put(node, node);

            // metodos e chamadas de construtores
            if(node.getType() == FlowGraphNode.METHOD_CALL) {
                MethodCallNode mc = (MethodCallNode) node;

                //System.out.println("Fazendo parse de " + 
                //    mc.getAbsTreeNode().toStringTree());

                SymbolTable st = mc.getSymbolTable();
                //System.out.println("Classinfo parsemc ST = " + st.toString());

                //System.out.println("Vou fazer o parse!");
                mc.parse(cdata, cdata.getPorts(), cdata.getParameters(),
                    cdata.getVariables());
            }
            else
            // construtores de statements new
            if(node.getType() == FlowGraphNode.BASIC_BLOCK) {
                BasicBlockNode bb = (BasicBlockNode) node;
                for(int i = 0;i < bb.statementsSize();i++) {
                    StatementInfo info = bb.getStatementInfo(i);
                    if(info.getType() == StatementInfo.VARDEF) {
                        VarDefStatementInfo vdinfo = (VarDefStatementInfo) info;
                        if(vdinfo.isNew()) {
                            vdinfo.parseNewStatement(cdata, cdata.getPorts(),
                                cdata.getParameters(), cdata.getVariables());
                        }
                    }
                }
            }
            for(int i = 0;i < node.outputSize();i++) {
                FlowGraphNode outn = node.getOutputNode(i);
                process.add(outn);

                // O addExceptionEdges ainda nao foi executado. Por isso
                // os catches ainda nao estao conectados
                if(node.getType() == FlowGraphNode.TRY_BEGIN) {
                    TryBeginNode tbeg = (TryBeginNode) node;
                    for(int k = 0;k < tbeg.catchSize();k++) {
                        outn = tbeg.getCatch(k);
                        process.add(outn);
                    }
                    if(tbeg.getFinally() != null) {
                        outn = tbeg.getFinally();
                        process.add(outn);
                    }
                }
            }
        }
    }

    public void addExceptionEdges(ClassData cdata) {
        HashMap processed = new HashMap();
        LinkedList process = new LinkedList();
        process.add(_source);
        while(process.size() > 0) {
            FlowGraphNode node = (FlowGraphNode) process.remove(0);
            if(processed.containsKey(node)) continue;

            if(node.getType() == FlowGraphNode.TRY_BEGIN) {
                TryBeginNode beg = (TryBeginNode) node;
                LinkedList catchNodes = new LinkedList();
                LinkedList catchTypes = new LinkedList();

                for(int i = 0;i < beg.catchSize();i++) {
                    CatchBeginNode cb = beg.getCatch(i);
                    catchNodes.add(cb);
                    String typen = cb.getTypeName();
                    Class t = Util.getType(typen, null, cdata.getPackage(),
                        cdata.getImports());
                    //_checkCatchException(t.getName());
                    catchTypes.add(t);
                }
                _searchTryBlock(node, catchNodes, catchTypes, processed,
                    beg.getFinally(), cdata);

                for(int i = 0;i < beg.catchSize();i++) {
                    process.add(beg.getCatch(i));
                }

                node = beg.getTryEnd();
            }
            else {
                processed.put(node, node);
            }

            if(node != null) {
                for(int i = 0;i < node.outputSize();i++) {
                    process.add(node.getOutputNode(i));
                }
            }
        }
    }

    /* Para cada MC node, descobre se tem um flowgraph nesse classinfo */
    public void linkMCNodes(ClassData owner) {
        for(int i = 0;i < _nodes.size();i++) {
            FlowGraphNode fgnode = (FlowGraphNode) _nodes.get(i);
            if(fgnode.getType() == FlowGraphNode.METHOD_CALL) {
                MethodCallNode mcnode = (MethodCallNode) fgnode;
                ClassData theowner = owner;

                if(mcnode.getCallerName().equals("super") &&
                         mcnode.getConstructor() == null) {
                    theowner = theowner.getSuperClass();
                    if(theowner == null) continue;
                }

                int parssize = mcnode.parametersSize();
                Object [] parstype;
                LinkedList ll = theowner.getMethod(mcnode.getMethodName());
                if(ll != null) {
                    for(int j = 0;j < ll.size();j++) {
                        STMethodEntry me = (STMethodEntry) ll.get(j);

                        FlowGraph fg = me.getFlowGraph();
                        ClassData fgowner = fg.getClassInfo();

                        Class ctype = mcnode.getCallerType();
                        try {
                            ClassLoader cl = ClassLoader.getSystemClassLoader();
                            Class c = cl.loadClass(fgowner.getName());

                            if(!Util.isSubClass(ctype, c)) continue;
                        }
                        catch(ClassNotFoundException ex) {
                            continue;
                        }
                        SymbolTable pars = fg.getMethodParameters();

                        if(pars.size() != parssize) {
                            continue;
                        }

                        if(parssize == 0) {   // nao tem parametros
                            mcnode.setFlowGraph(fg);
                            break;
                        }

                        parstype = mcnode.getParameterTypes();

                        boolean found = false;
                        Iterator ite = pars.iterator();
                        while(ite.hasNext()) {
                            STEntry par = (STEntry) ite.next();
                            found = false;
                            for(int k = 0;k < parstype.length;k++) {
                                if(parstype[k] != null &&
                                   parstype[k].equals(par.getType())) {
                                    parstype[k] = null;
                                    found = true;
                                    break;
                                }
                            }
                            if(!found) break;
                        }

                        if(found) {
                            mcnode.setFlowGraph(fg);
                            break;
                        }
                    }
                }
            }
        }
    }
    
    public void buildMethodGraph() {
        _methodGraph = new MethodGraph(this, _owner);
    }

    public SymbolTable getMethodParameters() {
        return _methodParameters;
    }

    public void removeNode(FlowGraphNode node) {
        if(node == _sink) {
            System.out.println("Error, trying to remove sink node!");
            return;
        }
        if(node == _source) {
            System.out.println("Error, trying to remove source node!");
            return;
        }
        _nodes.remove(node);
        _topologicalOrder = null;
    }

    public MethodGraph getMethodGraph() {
        return _methodGraph;
    }

    public String getKey() {
        return _key;
    }

    public void markGraph() {
        for(int i = 0;i < _nodes.size();i++) {
            FlowGraphNode node = (FlowGraphNode) _nodes.get(i);
            if(node.isDeleted()) continue;

            if(node.getType() == FlowGraphNode.METHOD_CALL) {
                MethodCallNode mcnode = (MethodCallNode) node;
                if(Util.isSubClass(mcnode.getCallerType(), IOPort.class)) {
                    String s = mcnode.getMethodName();
                    if(s.equals("hasRoom") || s.equals("hasToken") ||
                            s.equals("isKnown")) {

                        StatementInfo info = mcnode.getStatementInfo();
                        Iterator ite = info.defIndexedVarIterator();
                        while(ite.hasNext()) {
                            IndexedVarInfo vi = (IndexedVarInfo) ite.next();
                            LinkedList l = vi.varinfo.getUseFromChain(vi.index);
                            if(l == null) continue;

                            for(int j = 0;j < l.size();j++) {
                                VariableLocation loc = (VariableLocation) l.get(j);
                                if(loc.isPhiNode()) {
                                    // Isso aqui nao pode ser permitido, mas sera
                                    // considerado um loop nao contavel.
                                }
                                else {
                                    FlowGraphNode n = (FlowGraphNode) loc.getFGNode();
                                    if(n.getType() == FlowGraphNode.IF_BEGIN) {
                                        IfBeginNode ifbeg = (IfBeginNode) n;                                        

                                        // Verifica se a expressao booleana
                                        // do if eh composta so por metodos
                                        // de controle
                                        boolean ok = true;
                                        StatementInfo sinfo = ifbeg.getStatementInfo();
                                        Iterator useite = sinfo.useIndexedVarIterator();
                                        while(useite.hasNext()) {
                                            IndexedVarInfo use = (IndexedVarInfo) useite.next();
                                            if(use.varinfo == vi.varinfo) continue;

                                            if(use.index == 0) {
                                                ok = false;
                                                break;
                                            }

                                            LinkedList def = use.varinfo.getDefFromChain(use.index);
                                            for(int k = 0;k < def.size();k++) {
                                                VariableLocation defloc = (VariableLocation) def.get(k);
                                                if(defloc.isPhiNode()) {
                                                    ok = false;
                                                    break;
                                                }
                                                FlowGraphNode defnode = defloc.getFGNode();
                                                if(defnode.getType() != FlowGraphNode.METHOD_CALL) {
                                                    ok = false;
                                                    break;
                                                }
                                                MethodCallNode mcdef = (MethodCallNode) defnode;
                                                String mcname = mcdef.getMethodName();
                                                if(!mcname.equals("hasRoom") && !mcname.equals("hasToken") &&
                                                    !mcname.equals("isKnown")) {
                                                    ok = false;
                                                    break;
                                                }
                                            }
                                            if(!ok) break;
                                        }
                                        if(ok) {
                                            FlowGraphEdge edge = ifbeg.getElseEdge();
                                            edge.setSDFDead();
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        // Neste momento, so os primeiros nos dentro dos branches estao
        // marcados. Entao, tem que propagar para os outros nos.
        LinkedList top = getTopologicalOrder(false);
        for(int i = 0;i < top.size();i++) {
            FlowGraphNode node = (FlowGraphNode) top.get(i);
            if(node.isDeleted()) continue;
            if(node.inputSize() == 0) continue;

            boolean notmarked = false;
            Iterator ite = node.inputEdgesIterator();
            while(ite.hasNext()) {
                FlowGraphEdge edge = (FlowGraphEdge) ite.next();
                if(edge.isBack()) continue;
                if(!edge.isSDFDead()) {
                    notmarked = true;
                    break;
                }
            }
            if(!notmarked) {
                node.markSDF();
                for(int j = 0;j < node.outputSize();j++) {
                    FlowGraphEdge edge = node.getOutputEdge(j);
                    edge.setSDFDead();
                }
            }
        }
    }

    public boolean containsIOMethod(HashMap map) {
        if(map.containsKey(this)) return false;
        map.put(this, null);
        
        boolean ret = false;

        for(int i = 0;i < _nodes.size();i++) {
            FlowGraphNode n = (FlowGraphNode) _nodes.get(i);
            if(n.getType() == FlowGraphNode.METHOD_CALL) {
                if(MethodGraph.isIOFGNode(n)) return true;
                
                FlowGraph fg = ((MethodCallNode)n).getFlowGraph();
                if(fg != null && fg.isBuild()) {
                    ret = fg.containsIOMethod(map);
                    if(ret) return true;
                }
            }
        }

        return ret;
    }
    
    ///////////////////////////////////////////////////////////////////
    ////                        private methods                    ////

    private void _addNode(FlowGraphNode node) {
        node.setContainer(this);
        _nodes.add(node);
    }

    private FlowGraphNode _currentNode;

    private void _checkOpenedScopes(FlowGraphNode node, LinkedList lines) {
        if(node.getOpenedScopes() > 0) {
             for(int i = 0;i < node.getOpenedScopes();i++) {
                 Line l = new Line("{", null, node, 1, _ident, lines.size());
                 lines.add(l);
                 _ident += _IDENT_INC;
             }
        }
    }
    
    private void _checkClosedScopes(FlowGraphNode node, LinkedList lines) {
        if(node.getClosedScopes() > 0) {
            for(int k = 0;k < node.getClosedScopes();k++) {
                _ident -= _IDENT_INC;
                Line l = new Line("}", null, node, 1, _ident, lines.size());
                lines.add(l);
            }
        }
    }

    private void _codeGen(FlowGraphNode node,  FlowGraphNode stopNode, LinkedList lines) {
        String label;
        _currentNode = node;

        while(node.getType() != FlowGraphNode.SINK && node != stopNode) {
            _checkOpenedScopes(node, lines);
            switch(node.getType()) {
                case FlowGraphNode.BASIC_BLOCK: {
                    BasicBlockNode bb = (BasicBlockNode) node;
                    for(int i = 0;i < bb.statementsSize();i++) {
                        AST stat = bb.getStatement(i);
                        label = bb.getLabel(i);
                        if(label != null) {
                            // Nenhum FGnode e associado a essa linha
                            Line l = new Line(label + ":", null, bb, 1, _ident,
                               lines.size());
                            lines.add(l);
                        }
                        _generateLines(stat, node, _ident);
                        
                        // Eu sei que o StatPrinter so vai gerar uma 
                        // linha neste caso, entao ...

                        Line l = (Line) lines.getLast();
                        StatementInfo statinfo = bb.getStatementInfo(i);
                        statinfo.setLine(l);
                    }
                } break;

                case FlowGraphNode.METHOD_CALL: {
                    AST stat = node.getAbsTreeNode();

                    _addLabel(node, lines);
                    _generateLines(stat, node, _ident);
                } break;

                case FlowGraphNode.IF_BEGIN: {
                    IfBeginNode ifbeg = (IfBeginNode) node;
                    _addLabel(node, lines);

                    StringBuffer buf = new StringBuffer("if(");
                    _genPrinter.setAddColon(false);
                    buf.append(_getStatText(ifbeg.getCondition()));
                    buf.append(")");
                    Line l = new Line(buf.toString(), null, ifbeg, 1, _ident,
                        lines.size());
                    lines.add(l);
                    ifbeg.setConditionLine(l);

                    IfEndNode end = ifbeg.getIfEnd();

                    node = ifbeg.getThenNode();
                    if(node != null && node != end) {
                        _codeGen(node, end, lines);
                    }
                    else {
                        l = new Line("{ }", null, ifbeg, 1, _ident,
                            lines.size());
                        lines.add(l);
                    }

                    ifbeg.setThenEndLine((Line)lines.getLast());

                    node = ifbeg.getElseNode();
                    if(node.getType() != FlowGraphNode.IF_END) {
                        l = new Line("else", null, ifbeg, 1, _ident,
                            lines.size());
                        lines.add(l);
                        _codeGen(node, end, lines);
                        ifbeg.setElseEndLine((Line)lines.getLast());
                    }

                    if(end == null) return;
                    node = end;
                } break;

                case FlowGraphNode.WHILE_BEGIN: {
                    WhileBeginNode beg = (WhileBeginNode) node;
                    _addLabel(node, lines);

                    StringBuffer buf = new StringBuffer("while(");
                    _genPrinter.setAddColon(false);
                    buf.append(_getStatText(beg.getCondition()) + ")");
                    Line l = new Line(buf.toString(), null, beg, 1, _ident,
                        lines.size());
                    lines.add(l);
                    beg.setConditionLine(l);

                    WhileEndNode end = beg.getWhileEnd();
                    node = beg.getContinueNode();
                    
                    if(node != beg) {
                        _codeGen(node, beg, lines);
                    }
                    else {
                        l = new Line("{ }", null, beg, 1, _ident, lines.size());
                        lines.add(l);
                    }
                    beg.setEndLine((Line)lines.getLast());

                    node = end;
                } break;

                case FlowGraphNode.DO_BEGIN: {
                    _addLabel(node, lines);

                    DoBeginNode beg = (DoBeginNode) node;
                    DoEndNode end = beg.getDoEnd();
                    
                    Line l = new Line("do", null, node, 1, _ident, lines.size());
                    lines.add(l);
                    beg.setBegLine(l);

                    DoConditionNode cond = beg.getConditionNode();

                    node = node.getOutputNode(0);
                    if(node.getType() != FlowGraphNode.DO_CONDITION) {
                        _codeGen(node, cond, lines);
                    }
                    else {
                        l = new Line("{ }", null, node, 1, _ident, lines.size());
                        lines.add(l);
                    }
                    StringBuffer buf = new StringBuffer("while(");
                    _genPrinter.setAddColon(false);

                    buf.append(_getStatText(beg.getCondition()));
                    buf.append(");");

                    l = new Line(buf.toString(), null, beg, 1, _ident, lines.size());
                    lines.add(l);
                    beg.setConditionLine(l);

                    node = end;
                } break;
                
                case FlowGraphNode.FOR_BEGIN: {
                    ForBeginNode beg = (ForBeginNode) node;
                    _addLabel(node, lines);

                    StringBuffer buf = new StringBuffer("for(");
                    _genPrinter.setAddColon(false);

                    AST ast = beg.getInit();
                    ast = ast.getFirstChild();
                    if(ast != null) {
                        if(ast.getType() == JavaTokenTypes.ELIST) {
                            ast = ast.getFirstChild();
                            while(ast != null) {
                                buf.append(_getStatText(ast));
                                if(ast.getNextSibling() != null) {
                                   buf.append(",");
                                }
                                ast = ast.getNextSibling();
                            }
                            buf.append(";");
                        }
                        else {
                            buf.append(_getStatText(ast) + "; ");
                        }
                    }
                    else {
                        buf.append(";");   
                    }
                    ast = beg.getCondition().getFirstChild();
                    if(ast != null) {
                        buf.append(_getStatText(ast) + "; ");
                    }
                    else {
                        buf.append(";");   
                    }

                    ast = beg.getIterator();
                    ast = ast.getFirstChild();
                    if(ast != null) {
                        if(ast.getType() == JavaTokenTypes.ELIST) {
                            ast = ast.getFirstChild();
                            while(ast != null) {
                                buf.append(_getStatText(ast));
                                if(ast.getNextSibling() != null) {
                                   buf.append(",");   
                                }
                                ast = ast.getNextSibling();
                            }
                            buf.append(")");
                        }
                        else {
                            buf.append(_getStatText(ast) + ")");
                        }
                    }
                    else {
                        buf.append(")");
                    }
                    Line l = new Line(buf.toString(), null, beg, 1, _ident, lines.size());
                    lines.add(l);
                    beg.setConditionLine(l);

                    ForEndNode end = beg.getForEnd();
                    node = beg.getContinueNode();
                    
                    if(node != beg) {
                        _codeGen(node, beg, lines);
                        beg.setEndLine((Line)lines.getLast());
                    }
                    else {
                        l = new Line("{ }", null, beg, 1, _ident, lines.size());
                        lines.add(l);
                        beg.setEndLine(l);
                    }
                    
                    node = end;
                } break;

                case FlowGraphNode.BREAK: {
                    _addLabel(node, lines);

                    StringBuffer buf = new StringBuffer("break");
                    AST ast = ((BreakNode) node).getTarget();
                    if(ast != null) {
                        buf.append(" " + ast.getText());
                    }
                    buf.append(";");

                    Line l = new Line(buf.toString(), null, node, 1, _ident, lines.size());
                    lines.add(l);
                    ((BreakNode)node).setLine(l);
                    
                    _checkClosedScopes(node, lines);
                    return;
                }

                case FlowGraphNode.CONTINUE: {
                    _addLabel(node, lines);
                    
                    StringBuffer buf = new StringBuffer("continue");
                    AST ast = ((ContinueNode) node).getTarget();
                    if(ast != null) {
                        buf.append(" " + ast.getText());
                    }
                    buf.append(";");                                       
                    Line l = new Line(buf.toString(), null, node, 1, _ident, lines.size());                                        
                    lines.add(l);
                    ((ContinueNode)node).setLine(l);
                    
                    _checkClosedScopes(node, lines);
                    return;
                }

                case FlowGraphNode.RETURN: {
                    _addLabel(node, lines);

                    StringBuffer buf = new StringBuffer("return");
                    AST expr = ((ReturnNode)node).getExpression();
                    if(expr != null) {
                        _genPrinter.setAddColon(false);
                        buf.append(" "+ _getStatText(expr));
                    }
                    buf.append(";");
                    Line l = new Line(buf.toString(), null, node, 1, _ident, lines.size());
                    lines.add(l);
                    ((ReturnNode)node).setLine(l);

                    _checkClosedScopes(node, lines);
                    return;
                }

                case FlowGraphNode.THROW: {
                    _addLabel(node, lines);

                    StringBuffer buf = new StringBuffer("throw");
                    AST expr = ((ThrowNode)node).getExpression();
                    _genPrinter.setAddColon(false);
                    buf.append(" " + _getStatText(expr) + ";");
                    Line l = new Line(buf.toString(), null, node, 1, _ident, lines.size());
                    lines.add(l);
                    ((ThrowNode)node).setLine(l);

                    _checkClosedScopes(node, lines);
                    return;
                }

                case FlowGraphNode.SWITCH_BEGIN: {
                    _addLabel(node, lines);

                    SwitchBeginNode beg = (SwitchBeginNode) node;
                    StringBuffer buf = new StringBuffer("switch(");
                    AST expr = beg.getExpression();
                    _genPrinter.setAddColon(false);
                    buf.append(_getStatText(expr) + ") {");
                    Line l = new Line(buf.toString(), null, beg, 1, _ident, lines.size());
                    lines.add(l);
                    beg.setConditionLine(l);

                    SwitchEndNode end = beg.getSwitchEnd();

                    _genPrinter.setAddColon(false);
                    _ident += _IDENT_INC;
                    for(int k = 0;k < beg.outputSize();k++) {
                        FlowGraphEdge edge = beg.getOutputEdge(k);
                        node = edge.getTo();
                        FlowGraphNode cend = beg.getCaseEndNode(k);
                        if(node.getType() != FlowGraphNode.SWITCH_END) {
                            SwitchEdge einfo = (SwitchEdge) edge.getEdgeInfo();
                            LinkedList conds = einfo.getConditions();
                            if(conds.size() == 0) {
                                buf = new StringBuffer("default:");
                            }
                            else
                            if(conds.size() > 1) {
                                for(int i = 0;i < conds.size() - 1;i++) {
                                    expr = (AST) conds.get(i);
                                    buf = new StringBuffer("case " +
                                       _getStatText(expr) + ":");
                                    l = new Line(buf.toString(), null, beg,
                                        1, _ident, lines.size());
                                    lines.add(l);
                                }
                                expr = (AST) conds.get(conds.size() - 1);
                                buf = new StringBuffer("case " +
                                    _getStatText(expr) + ":");
                            }
                            else
                            if(conds.size() == 1) {
                                expr = (AST) conds.get(0);
                                buf = new StringBuffer("case " +
                                    _getStatText(expr) + ":");
                            }
                            l = new Line(buf.toString(), null, beg, 1, _ident, lines.size()); 
                            lines.add(l);

                            _codeGen(node, cend, lines);

                            if(k < beg.outputSize() - 1) {
                                l = new Line("", null, beg, 1, _ident, lines.size());
                                lines.add(l);
                            }
                        }
                    }
                    _ident -= _IDENT_INC;
                    l = new Line("}", null, beg, 1, _ident, lines.size());
                    lines.add(l);
                    beg.setEndLine(l);

                    node = end;
                } break;
                
                case FlowGraphNode.TRY_BEGIN: {
                    _addLabel(node, lines);

                    TryBeginNode beg = (TryBeginNode) node;
                    TryEndNode end = beg.getTryEnd();

                    Line l = new Line("try", null, beg, 1, _ident, lines.size());
                    lines.add(l);
                    beg.setBegLine(l);

                    node = beg.getOutputNode(0);
                    _codeGen(node, end, lines);
                    beg.setEndLine((Line)lines.getLast());

                    for(int k = 0;k < beg.catchSize();k++) {
                        CatchBeginNode cbeg = beg.getCatch(k);
                        _addLabel(cbeg, lines);

                        l = new Line("catch(" + cbeg.getParameterDef() +
                            ")", null, beg, 1, _ident, lines.size());
                        lines.add(l);
                        cbeg.setBegLine(l);

                        node = cbeg.getOutputNode(0);
                        CatchEndNode cend = cbeg.getCatchEnd();
                        if(node != cend) {
                            _codeGen(node, cend, lines);
                        }
                        else {
                            l = new Line("{ }", null, cbeg, 1, _ident, lines.size());
                            lines.add(l);
                        }
                        beg.setEndLine((Line)lines.getLast());
                    }

                    FinallyBeginNode fbeg = beg.getFinally();
                    if(fbeg != null) {
                        _addLabel(fbeg, lines);

                        l = new Line("finally", null, fbeg, 1, _ident, lines.size());
                        lines.add(l);
                        fbeg.setBegLine(l);
                        
                        node = fbeg.getOutputNode(0);
                        FinallyEndNode fend = fbeg.getFinallyEnd();
                        if(node != fend) {
                            _codeGen(node, fend, lines);
                        }
                        else {                            
                            l = new Line("{ }", null, fbeg, 1, _ident, lines.size());
                            lines.add(l);
                        }
                        fbeg.setEndLine((Line)lines.getLast());
                        node = fend;
                    }
                    else {
                        // Ele tem que ter finally ou catch.
                        node = end;
                        // O end pode ser null, no caso que o corpo do try
                        // e todos os catches tem return no fim. Entao tem
                        // que retornar.
                        if(end == null) {
                            return;
                        }
                    }
                } break;
                
                case FlowGraphNode.SYNC_BEGIN: {
                    _addLabel(node, lines);
                    
                    SyncBeginNode beg = (SyncBeginNode) node;
                    SyncEndNode end = beg.getSyncEnd();

                    StringBuffer buf = new StringBuffer("synchronized(");
                    AST expr = beg.getExpression();
                    _genPrinter.setAddColon(false);
                    buf.append(_getStatText(expr) + ")");
                    
                    Line l = new Line(buf.toString(), null, beg, 1, _ident, lines.size());
                    lines.add(l);
                    beg.setBegLine(l);

                    node = beg.getOutputNode(0);
                    if(node != end) {
                        _codeGen(node, end, lines);
                        beg.setEndLine((Line)lines.getLast());
                    }
                    else {
                        l = new Line("{ }", null, end, 1, _ident, lines.size());
                        lines.add(l);
                        beg.setEndLine(l);
                    }

                    node = end;
                } break;

                case FlowGraphNode.INNER_CLASS: {
                    AST stat = node.getAbsTreeNode();
                    InnerClassNode inner = (InnerClassNode) node;
                    _addLabel(node, lines);

                    Line l;
                    // classe locais nao precisam disso
                    if(inner.getClassType() == InnerClassNode.ANONYMOUS) {
                        // isso aqui so vai gerar ate o .... type() ...
                        _genPrinter.setAddColon(false);
                        String s = _getStatText(stat);
                        
                        l = new Line(s + " {", null, node, 1, _ident, lines.size());
                        lines.add(l);
                        inner.setBegLine(l);

                        _ident += _IDENT_INC;
                    }

                    LinkedList code = ((InnerClassNode) node).getCode();
                    for(int i = 0;i < code.size();i++) {
                        l = (Line) code.get(i);
                        // Eu duplico a linha, para o numero da linha 
                        // ficar correto
                        Line newl = l.duplicate();
                        newl.setIdent(l.getIdent() + _ident);
                        newl.setNumber(lines.size());
                        lines.add(newl);
                    }

                    if(inner.getClassType() == InnerClassNode.ANONYMOUS) {
                        _ident -= _IDENT_INC;

                        l = new Line("};", null, node, 1, _ident, lines.size());
                        lines.add(l);
                        inner.setEndLine(l);
                    }
                } break;

                default: {
                    return;
                }
            }
            _checkClosedScopes(node, lines);
            node = node.getOutputNode(0);
        }
    }

    private void _addLabel(FlowGraphNode node, LinkedList lines) {
        String label = node.getLabel();
        if(label != null) {
            Line l = new Line(label + ":", null, node, 1, _ident, lines.size());
            lines.add(l);
        }
    }

    private void _generateLines(AST stat, FlowGraphNode node, int ident) {
        try {
            _statPrinter.setIdent(ident);
            _statPrinter.setFGNode(node);
            _statPrinter.statement(stat);
        }
        catch(RecognitionException ex) {
            System.out.println("RecognitionException:");
            System.out.println(ex);
        }
    }

    private String _getStatText(AST stat) {
        Line l = null;
        try {
            _genPrinter.setIdent(0);
            // O genprinter e feito para traduzir um statement, assim, nao tem
            // um fg associado.
            _genPrinter.setFGNode(null);
            _genPrinter.statement(stat);
            if(_tmpList.size() != 0) {
                l = (Line) _tmpList.get(0);
                _tmpList.clear();
            }
            else {
                return "";
            }
        }
        catch(RecognitionException ex) {
            System.out.println("RecognitionException:");
            System.out.println(ex);   
        }
        return l.getText();
    }

    private void _printGraphNode(FlowGraphNode node, PrintStream ps, boolean linkInfo) {
        ps.print("Node " + node.toString());
        switch(node.getType()) {
            case FlowGraphNode.SOURCE: {
                ps.println(" : Source node");
            } break;

            case FlowGraphNode.SINK: {
                ps.println(" : Sink node");
            } break;
            
            case FlowGraphNode.SYNC_BEGIN: {
                ps.println(" : Synchronized begin");
            } break;

            case FlowGraphNode.SYNC_END: {
                ps.println(" : Synchronized end");
            } break;

            case FlowGraphNode.TRY_BEGIN: {
                ps.println(" : Try begin");
            } break;

            case FlowGraphNode.TRY_END: {
                ps.println(" : Try end");
            } break;

            case FlowGraphNode.BASIC_BLOCK: {
                ps.println(" : Basic Block Node");
            } break;
            
            case FlowGraphNode.IF_BEGIN: {
                ps.println(" : If Begin");
            } break;
            
            case FlowGraphNode.IF_END: {
                ps.println(" : If End");
            } break;
            
            case FlowGraphNode.RETURN: {
                ps.println(" : Return");   
            } break;
            
            case FlowGraphNode.WHILE_BEGIN: {
                ps.println(" : While Begin");                        
            } break;
            
            case FlowGraphNode.WHILE_END: {
                ps.println(" : While End");                        
            } break;

            case FlowGraphNode.BREAK: {
                ps.println(" : Break");
            } break;
            
            case FlowGraphNode.CONTINUE: {
                ps.println(" : Continue");
            } break;
            
            case FlowGraphNode.METHOD_CALL: {
                ps.println(" : Method Call");                
            } break;

            case FlowGraphNode.DO_BEGIN: {
                ps.println(" : Do Begin");
            } break;
            
            case FlowGraphNode.DO_END: {
                ps.println(" : Do End");
            } break;
            
            case FlowGraphNode.DO_CONDITION: {
                ps.println(" : Do Condition");
            } break;
            
            case FlowGraphNode.SWITCH_BEGIN: {
                ps.println(" : Switch Begin");
            } break;
            
            case FlowGraphNode.SWITCH_END: {
                ps.println(" : Switch End");
            } break;

            case FlowGraphNode.FOR_BEGIN: {
                ps.println(" : For Begin");                        
            } break;

            case FlowGraphNode.FOR_END: {
                ps.println(" : For End");                        
            } break;
            
            case FlowGraphNode.THROW: {
                ps.println(" : Throw");
            } break;
            
            case FlowGraphNode.CATCH_BEGIN: {
                ps.println(" : Catch Begin");
            } break;
            
            case FlowGraphNode.CATCH_END: {
                ps.println(" : Catch End");
            } break;
            
            case FlowGraphNode.FINALLY_BEGIN: {
                ps.println(" : Finally Begin");
            } break;
            
            case FlowGraphNode.FINALLY_END: {
                ps.println(" : Finally End");
            } break;
            
            case FlowGraphNode.INNER_CLASS: {
                ps.println(" : Inner Class");
            } break;
        }

        if(linkInfo) {
            ps.print("connected to: ");
            Iterator ite = node.outputEdgesIterator();
            while(ite.hasNext()) {
                FlowGraphEdge edge = (FlowGraphEdge) ite.next();
                FlowGraphNode n = edge.getTo();
                ps.print(n.toString() + " | ");
            }
            ps.println("\n");
        }
    }

    /* ps e o .dot do FG
       dout e o arquivo de dados dos nos
       dout2 e o das arestas
    */
    private void _debug(PrintStream ps, DataOutputStream dout, DataOutputStream dout2) {
        StringBuffer buf = new StringBuffer("digraph \" " + _methodName +
          "\" {\n");
        buf.append("edge [ style = \"setlinewidth(1)\" ];\n");
        buf.append("graph [bb = \"0,0,1042,397\"];\n\n");

        try {
            dout.writeInt(_nodes.size());
            dout2.writeInt(_edges.size());
        } 
        catch(IOException ex) {
            System.out.println(ex);
        }

        for(int i = 0;i < _nodes.size();i++) {
            FlowGraphNode node = (FlowGraphNode) _nodes.get(i);

            if(node.isSDFMarked()) {
                buf.append(node.hashCode() + " [shape=circle,label=\"" +
                    node.typeToString() + "\",color=\"blue\"];\n");
            }
            else {
                buf.append(node.hashCode() + " [shape=box,label=\"" +
                    node.typeToString() + "\"];\n");
            }

            node.debug(dout);

            for(int j = 0;j < node.outputSize();j++) {
                FlowGraphNode n = node.getOutputNode(j);
                FlowGraphEdge edge = node.getOutputEdge(j);
                buf.append(node.hashCode() + " -> " + n.hashCode() + 
                    " [id=" + edge.hashCode() + ",color=" + 
                    _getEdgeColor(edge) + "];\n");
            }
        }
        buf.append("}");
        ps.print(buf.toString());

        for(int i = 0;i < _edges.size();i++) {
            FlowGraphEdge edge = (FlowGraphEdge) _edges.get(i);
            edge.debug(dout2);
        }
    }

    private String _getEdgeColor(FlowGraphEdge edge) {
        if(edge.isSDFDead()) return "yellow";

        EdgeInfo info = edge.getEdgeInfo();
        if(info == null) return "black";
        switch(info.getType()) {
            case EdgeInfo.BACK: return "red";
            case EdgeInfo.SWITCH: return "blue";
            case EdgeInfo.EXCEPTION: return "green";
        }
        return "black";
    }
    
    private void _searchTryBlock(FlowGraphNode tbeg, LinkedList catchNodes, 
            LinkedList catchTypes, HashMap processed, 
            FinallyBeginNode finallyBegin, ClassData cdata) {

        LinkedList process = new LinkedList();
        for(int i = 0;i < tbeg.outputSize();i++) {
            process.add(tbeg.getOutputNode(i));
        }

        ExceptionScanner scanner = new ExceptionScanner();
        while(process.size() > 0) {
            FlowGraphNode node = (FlowGraphNode) process.remove(0);
            if(processed.containsKey(node)) continue;
            processed.put(node, node);

            switch(node.getType()) {

                case FlowGraphNode.METHOD_CALL: {
                    MethodCallNode mcnode = (MethodCallNode) node;
                    _methodCallThrows(mcnode, mcnode.getAbsTreeNode(), 0,
                        catchNodes, catchTypes, finallyBegin);

                    //_createExceptionConnections(scanner, mcnode.getAbsTreeNode(),
                    //    fg, mcnode, catchNodes, catchTypes);
                } break;

                case FlowGraphNode.BASIC_BLOCK: {
                    _basicBlockThrows((BasicBlockNode)node, catchNodes, catchTypes,
                        scanner, finallyBegin);
                } break;

                case FlowGraphNode.IF_BEGIN: {
                    IfBeginNode ifbeg = (IfBeginNode) node;
                    _createExceptionConnections(scanner, ifbeg.getCondition(),
                        ifbeg, 0, catchNodes, catchTypes, finallyBegin);
                } break;

                case FlowGraphNode.DO_CONDITION: {
                    DoConditionNode cond = (DoConditionNode) node;
                    _createExceptionConnections(scanner, cond.getCondition(),
                        cond, 0, catchNodes, catchTypes, finallyBegin);
                } break;

                case FlowGraphNode.FOR_BEGIN: {
                    ForBeginNode fbeg = (ForBeginNode) node;
                    _createExceptionConnections(scanner, fbeg.getInit(),
                        fbeg, 0, catchNodes, catchTypes, finallyBegin);
                        
                    _createExceptionConnections(scanner, fbeg.getCondition(),
                        fbeg, 0, catchNodes, catchTypes, finallyBegin);
                        
                    _createExceptionConnections(scanner, fbeg.getIterator(),
                        fbeg, 0, catchNodes, catchTypes, finallyBegin);
                } break;

                case FlowGraphNode.RETURN: {
                    ReturnNode retn = (ReturnNode) node;
                    AST expr = retn.getExpression();
                    if(expr != null) {
                        _createExceptionConnections(scanner, retn.getExpression(),
                            retn, 0, catchNodes, catchTypes, finallyBegin);
                    }
                } break;
                
                case FlowGraphNode.SWITCH_BEGIN: {
                    SwitchBeginNode swbeg = (SwitchBeginNode) node;
                    _createExceptionConnections(scanner, swbeg.getExpression(),
                        swbeg, 0, catchNodes, catchTypes, finallyBegin);
                } break;

                case FlowGraphNode.THROW: {
                    ThrowNode th = (ThrowNode) node;
                    _createExceptionConnections(scanner, th.getExpression(),
                        th, 0, catchNodes, catchTypes, finallyBegin);
                } break;
                
                case FlowGraphNode.WHILE_BEGIN: {
                    WhileBeginNode wbeg = (WhileBeginNode) node;
                    _createExceptionConnections(scanner, wbeg.getCondition(),
                        wbeg, 0, catchNodes, catchTypes, finallyBegin);
                } break;

                case FlowGraphNode.TRY_BEGIN: {
                    TryBeginNode beg = (TryBeginNode) node;
                    for(int i = 0;i < beg.catchSize();i++) {
                        CatchBeginNode cb = beg.getCatch(i);
                        catchNodes.add(cb);
                        String typen = cb.getTypeName();
                        Class t = Util.getType(typen, null, cdata.getPackage(),
                            cdata.getImports());
                        //_checkCatchException(t.getName());
                        catchTypes.add(t);
                    }
                    _searchTryBlock(node, catchNodes, catchTypes, processed,
                        beg.getFinally(), cdata);

                    for(int i = 0;i < beg.catchSize();i++) {
                        catchNodes.removeLast();
                        catchTypes.removeLast();
                        process.add(beg.getCatch(i));
                    }
                    node = beg.getTryEnd();
                } break;
            }

            if(node != null) {
                for(int i = 0;i < node.outputSize();i++) {
                    FlowGraphNode outn = node.getOutputNode(i);
                    // Testa se o destino da aresta esta fora do corpo
                    // do try block
                    if(outn.getScope() > tbeg.getScope()) {
                        process.add(outn);
                    }
                }
            }
        }
    }
    
    // Dado uma lista de objetos Exception do no, cria as conexoes com
    // os catchnodes.
    private void _createExceptionConnections(ExceptionScanner scanner,
            AST ast, FlowGraphNode fgnode, int bbstatement,
            LinkedList catchNodes, LinkedList catchTypes, FinallyBeginNode finallyBegin) {
        scanner.reset();
        scanner.setBBStatement(bbstatement);
        try {
            scanner.process(ast);
        }
        catch(RecognitionException ex) {
            System.out.println("Exception no scanner de exceptions connections: " +
                ex.toString());
        }
        Iterator exceptions = scanner.exceptionIterator();
        boolean found = false;
        while(exceptions.hasNext()) {
            ExceptionEdgeData data = (ExceptionEdgeData) exceptions.next();
            Class exception = data.getExceptionType();
            for(int j = catchNodes.size() - 1;j >= 0;j--) {
                CatchBeginNode catchbeg = (CatchBeginNode) catchNodes.get(j);
                Class type  = (Class) catchTypes.get(j);
                if(type.equals(exception)  || 
                       Util.isSubClass(exception, type)) {
                    if(fgnode.hasOutput((FlowGraphNode) catchbeg)) {
                        FlowGraphEdge edge = fgnode.getOutputEdge(catchbeg);
                        ExceptionEdge ex = (ExceptionEdge) edge.getEdgeInfo();
                        ex.addData(data);
                        found = true;
                        break;
                    }
                    else {
                        FlowGraphEdge edge = connect(fgnode,
                            (FlowGraphNode) catchNodes.get(j));
                        ExceptionEdge ex = new ExceptionEdge();
                        ex.addData(data);
                        edge.setEdgeInfo(ex);
                        found = true;
                        break;
                    }
                }
            }
            // Se nao achou nada, tem que ligar com o finally, e adicionar a
            // aresta do finally end pro sink.
            if(!found) {
                if(finallyBegin != null) {
                    if(fgnode.hasOutput(finallyBegin)) {
                        FlowGraphEdge edge = fgnode.getOutputEdge(finallyBegin);
                        ExceptionEdge ex = (ExceptionEdge) edge.getEdgeInfo();
                        ex.addData(data);
                    }
                    else {
                        FlowGraphEdge edge = connect(fgnode, finallyBegin);
                        ExceptionEdge ex = new ExceptionEdge();
                        ex.addData(data);
                        edge.setEdgeInfo(ex);
                    }

                }
            }
            else {
                found = false;
            }
        }
    }

    // Determina se e um call de metodo do ptolemy ou nao. Se nao for,
    //tem que colocar todas as arestas.
    //   Pode ser usado por um methodcallNode ou por um Bb, quando for
    //   construtor. 
    private void _methodCallThrows(FlowGraphNode mc,
            AST statement, int bbstatement, LinkedList catchNodes, 
            LinkedList catchTypes, FinallyBeginNode finallyBegin) {

        // Senao, tem que criar aresta para todos os nos
        // de catch
        for(int j = 0;j < catchNodes.size();j++) {
            CatchBeginNode cbeg = (CatchBeginNode) catchNodes.get(j);
            if(!mc.hasOutput(cbeg)) {
                FlowGraphEdge edge = connect(mc, cbeg);
                ExceptionEdge einfo = new ExceptionEdge();
                edge.setEdgeInfo(einfo);

                Class c = (Class) catchTypes.get(j);
                ExceptionEdgeData data = new ExceptionEdgeData(0, bbstatement, 
                    statement, c);
                einfo.addData(data);
            }
            else {
                FlowGraphEdge edge = mc.getOutputEdge(cbeg);
                ExceptionEdge einfo = (ExceptionEdge) edge.getEdgeInfo();

                Class c = (Class) catchTypes.get(j);
                ExceptionEdgeData data = new ExceptionEdgeData(0, bbstatement, 
                    statement, c);
                einfo.addData(data);
            }
        }
        
        // Tem que adicionar uma aresta para o finally.
        if(finallyBegin != null) {
            if(mc.hasOutput(finallyBegin)) {
                FlowGraphEdge edge = mc.getOutputEdge(finallyBegin);
                ExceptionEdge ex = (ExceptionEdge) edge.getEdgeInfo();
                ExceptionEdgeData data = new ExceptionEdgeData(0, bbstatement,
                    statement, null);
                ex.addData(data);
            }
            else {
                FlowGraphEdge edge = connect(mc, finallyBegin);
                ExceptionEdge ex = new ExceptionEdge();
                edge.setEdgeInfo(ex);
                ExceptionEdgeData data = new ExceptionEdgeData(0, bbstatement,
                    statement, null);
                ex.addData(data);
            }
            
        }
 
    }
    
    private void _basicBlockThrows(BasicBlockNode bb,
            LinkedList catchNodes, LinkedList catchTypes,
            ExceptionScanner scanner, FinallyBeginNode finallyBegin) {

        for(int n = 0;n < bb.statementsSize();n++) {
            StatementInfo statinfo = bb.getStatementInfo(n);
            if(statinfo.getType() == StatementInfo.VARDEF) {
                VarDefStatementInfo vardef = (VarDefStatementInfo) statinfo;
                // Verifica se e um construtor ou nao
                if(vardef.isNew()) {
                    // Se for construtor, entao e que nem mc.
                    _methodCallThrows(bb, bb.getStatement(n), n,
                        catchNodes, catchTypes, finallyBegin);
                 }
                 else {
                     _createExceptionConnections(scanner, bb.getStatement(n),
                        bb, n, catchNodes, catchTypes, finallyBegin);
                 }
            }
            else {
               _createExceptionConnections(scanner, bb.getStatement(n),
                        bb, n, catchNodes, catchTypes, finallyBegin);
            }
        }
    }

    ///////////////////////////////////////////////////////////////////
    ////                        private variables                  ////

    // Statements para esse flowgraph. Comeca a partir da slist do 
    // methoddef.
    private AST _stats;

    private boolean _notBuild;
    private boolean _opPerformed;
    
    private SymbolTable _methodParameters;
    
    private FlowGraphNode _source;
    private FlowGraphNode _sink;

    private LinkedList _nodes;
    private LinkedList _edges;

    private String _methodName;

    private int _ident;
    private static final int _IDENT_INC = 4;
    
    private StatPrinter _statPrinter;
    
    private ClassData _owner;

    private int _uniqueCount;
    private int _uniqueSCCount;

    private LinkedList _topologicalOrder;
    private LinkedList _reverseTopologicalOrder;

    private SSA _ssa;

    private MethodGraph _methodGraph;

    private String _key;
    
    private boolean _isConstructor; 
    
    class FGNodeComparator implements Comparator {
        public int compare(Object o1, Object o2) {
            FlowGraphNode n1 = (FlowGraphNode) o1;
            FlowGraphNode n2 = (FlowGraphNode) o2;

            return n1.getScope() - n2.getScope();
        }

        public boolean equals(Object obj) {
            return false;
        }
    }
    
    private StatPrinter _genPrinter;
    private LinkedList _tmpList;
}